package main;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import model.Message;
import model.User;

//服务器类
public class ChatServer extends JFrame {
	public static final int PORT = 1111; // 默认端口
	private ServerSocket ss = null;
	private List<Client> clientList = new ArrayList<Client>(); // 客户端集合

	JTextArea countArea = new JTextArea(20, 10); // 统计
	JTextArea listArea = new JTextArea(20, 12); // 用户列表
	JTextArea logArea = new JTextArea(20, 25); // 上下线日志
	JTextField inputField = new JTextField(35);// 公告
	JButton button = new JButton("发公告");// 公告输入确认按钮

	public static void main(String[] args) {
		new ChatServer().start();

	}

	public ChatServer() {
		super("服务器");
		this.setSize(580, 430);
		this.setResizable(false);
		this.setLocationRelativeTo(null);
		this.addWindowListener(new WindowAdapter() {

			@Override
			public void windowClosing(WindowEvent arg0) {
				System.exit(0);
			}

		});

		button.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				if (inputField.getText().length() == 0) {
					return;
				}

				for (Client c : clientList) {
					if (c.username.length() > 0) { // 发公告
						c.send(new Message(inputField.getText(), null, "all"));
					}
				}
				inputField.setText("");
			}
		});

		this.setLayout(new FlowLayout());

		countArea.setEditable(false);
		listArea.setEditable(false);
		logArea.setEditable(false);
		inputField.setPreferredSize(new Dimension(50, 26));
		this.add(countArea);
		this.add(listArea);
		this.add(logArea);
		this.add(inputField);
		this.add(button);

		this.setVisible(true);

		this.start();
	}

	// 开启服务器
	private void start() {
		try {
			ss = new ServerSocket(PORT);
			while (true) {
				Socket s = ss.accept();// 接受客户端连接

				Client c = new Client(s);
				new Thread(c).start();

				clientList.add(c);
			}
		} catch (BindException e) {
			JOptionPane.showMessageDialog(null, "服务器已启动！");
			System.exit(-1);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	// 刷新数据
	public void refreshInfo(String username, boolean flag) {
		// 统计
		countArea.setText("在线人数：" + clientList.size());

		// 列表
		listArea.setText("在线用户：\n");
		for (Client c : clientList) {
			listArea.append(c.username + "\n");
		}
		// 日志
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 设置日期格式
		logArea.append(sdf.format(new Date()) + "--" + username
				+ (flag ? "--上线" : "--下线") + "\n");
	}

	// 客户端类
	class Client implements Runnable {
		private String username = "";
		private Socket socket = null;

		private ObjectInputStream ois = null;
		private ObjectOutputStream oos = null;

		public Client(Socket s) {
			try {
				this.socket = s;
				oos = new ObjectOutputStream(socket.getOutputStream());
				ois = new ObjectInputStream(socket.getInputStream());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		// 发送消息
		private void send(Message msg) {
			try {
				oos.writeObject(msg);
				oos.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		// 发送用户列表
		private void sendUsernameList(List<User> usernameList) {
			try {
				oos.writeObject(usernameList);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		// 上线通知
		private void onlineInform() {
			List<User> usernameList = new ArrayList<>();
			for (Client c : clientList) {
				if (c != this) {
					usernameList.add(new User(c.username));
				}
			}
			this.sendUsernameList(usernameList); // 给自己发送用户列表

			Message m = new Message(this.username, null, null);
			for (Client c : clientList) { // 给其他人发送包含自己用户名的Message通知上线
				if (c != this) {
					c.send(m);
				}
			}
		}

		// 验证是否重复登录
		public boolean repeatLogin(String username) {
			for (Client c : clientList) {
				if (c.username.equals(username)) {
					return true;
				}
			}
			return false;
		}

		@Override
		public void run() {
			boolean flag = false; // 注册或登录是否成功
			while (true) {
				Map<String, String> user;
				try {
					user = (Map<String, String>) ois.readObject();
					if (user.get("status").equals("register")) {
						user.remove("status"); // 移除注册的参数
						if (DataAction.getInstance().register(user)) { // 注册成功
							flag = true;
						}
					} else if (user.get("status").equals("login")) {
						user.remove("status"); // 移除登录的参数
						if (DataAction.getInstance().login(user)
								&& !repeatLogin(user.get("username"))) { // 登录成功
							flag = true;
						}
					}

					oos.writeObject(flag); // 返回给客户端登录注册是否成功

					if (flag) {
						this.username = user.get("username");
						this.onlineInform(); // 上线通知
						refreshInfo(this.username, true);
					} else {
						clientList.remove(this); // 登录或注册失败，移除该客户端
					}

					while (flag) { // 接收和发送消息，下线通知

						Message msg = (Message) ois.readObject();

						if (msg.getFrom() != null && msg.getTo() == null) { // 公聊
							for (Client c : clientList) {
								c.send(msg);
							}
						} else if (msg.getFrom() != null && msg.getTo() != null) { // 私聊
							for (Client c : clientList) {
								if (c.username.equals(msg.getFrom())
										|| c.username.equals(msg.getTo())) {
									c.send(msg);
								}
							}
						} else { // 下线通知
							for (Client c : clientList) {
								if (c.username.equals(msg.getContent())) {
									clientList.remove(c);
									refreshInfo(msg.getContent(), false);
									break;
								}
							}
							for (Client c : clientList) {
								c.send(msg);
							}
						}
					}

				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				} catch (SocketException e) { // 远程客户端断开连接
					clientList.remove(this);
					return;
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

		}

	}

}
